import type { ElectronApplication, Page } from 'playwright'
import { test as base } from '@playwright/test'
import { _electron as electron } from 'playwright'
import { inspect } from 'node:util'

// 为 Electron 项目提供 worker 级别的 app 实例，以及每个测试的首个窗口引用
// - app: 每个 worker 启动一次 Electron，所有该 worker 下的 spec 共享
// - win: 每个测试获取首个窗口，并等待 DOMContentLoaded
type TestFixtures = { win: Page; electronApp: ElectronApplication }
type WorkerFixtures = { app: ElectronApplication }

async function getLayoutWindow(app: ElectronApplication): Promise<Page | undefined> {
  const webContentsId = await app.evaluate<number>(async () => {
    try {
      while (!global.browserManager) {
        console.log('等待浏览器管理器初始化...')
        await new Promise(resolve => setTimeout(resolve, 100))
      }
      console.log('浏览器管理器已就绪')
      return global.browserManager.mainWindow.layoutTab.data.webContentsId
    } catch {
      return null
    }
  })

  const pages = app.windows()
  for (const page of pages) {
    const pageWebContentsId = await page.evaluate<number>(
      () => (_pre_.tab.getData() as any).webContentsId
    )
    if (pageWebContentsId === webContentsId) {
      return page
    }
  }
}

export const test = base.extend<TestFixtures, WorkerFixtures>({
  app: [
    // eslint-disable-next-line no-empty-pattern
    async ({}, use) => {
      const app = await electron.launch({
        args: ['dist/main.js'],
        env: {
          NODE_ENV: 'development',
          ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
          theme: 'dark',
          E2E: 'true'
        }
      })
      // 转发主进程 console（保留 error/warn 等级与彩色对象）
      app.on('console', async msg => {
        const raw = await Promise.all(
          msg.args().map(a => a.jsonValue().catch(() => '[unserializable]'))
        )
        const vals = raw.map(v =>
          typeof v === 'string' ? v : inspect(v, { colors: true, depth: null })
        )
        const t = msg.type()
        if (t === 'error') console.error('[主进程]', ...vals)
        else if (t === 'warning') console.warn('[主进程]', ...vals)
        else console.log('[主进程]', ...vals)
      })

      // 转发渲染进程 console，并保留 error/warn 等级
      app.on('window', page => {
        page.on('console', async msg => {
          const raw = await Promise.all(
            msg.args().map(a => a.jsonValue().catch(() => '[unserializable]'))
          )
          const vals = raw.map(v =>
            typeof v === 'string' ? v : inspect(v, { colors: true, depth: null })
          )
          const t = msg.type()
          if (t === 'error') console.error('[渲染进程]', ...vals)
          else if (t === 'warning') console.warn('[渲染进程]', ...vals)
          else console.log('[渲染进程]', ...vals)
        })
      })
      try {
        await use(app)
      } finally {
        await app.close()
      }
    },
    { scope: 'worker' }
  ],

  win: [
    async ({ app }, use) => {
      const win = (await getLayoutWindow(app)) || (await app.firstWindow())
      await win.waitForLoadState('domcontentloaded')
      // 尝试等待 layoutBrowser 的选择器；若不存在则退化为网络空闲
      try {
        await win.waitForSelector('[data-testid="layout-ready"]', {
          state: 'attached',
          timeout: 10_000
        })
      } catch {
        await win.waitForLoadState('networkidle')
      }
      await use(win)
    },
    { auto: true }
  ],

  // 将 worker 级别的 app 暴露为测试级别的 electronApp，便于用例访问主进程
  electronApp: async ({ app }, use) => {
    await use(app)
  }
})
